package com.ctrip.corp.obt.shard.domain.dbmetainfo;

import static com.ctrip.corp.obt.shard.sql.mybatis.interceptor.compatibility.constant.CompatibilityConstant.DM_SQL;
import static com.ctrip.corp.obt.shard.sql.mybatis.interceptor.compatibility.constant.CompatibilityConstant.KING_BASE_SQL;
import static com.ctrip.corp.obt.shard.sql.mybatis.interceptor.compatibility.constant.CompatibilityConstant.TYPE_PATTERN;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.ctrip.corp.obt.generic.utils.StringUtils;
import com.ctrip.corp.obt.shard.constants.DbType;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * 描述
 *
 * @author x.shen
 * @since 2024/3/14
 */
@Data
@Slf4j
public class DatabaseMetaInfo {

    private DbType databaseType;
    /**
     * 表解析<表名，<列名>>
     */
    private Map<String, Set<String>> tableWithColumnNameMap;
    /**
     * 列解析<列名，类型>
     */
    private Map<String, String> columnWithTypeMap;

    /**
     * 通过sql语句来获取数据库元信息
     * 
     * @param connection
     * @param dbType
     * @return
     */
    public static DatabaseMetaInfo buildMetaInfoWithSql(Connection connection, String jdbcUrl, DbType dbType) {
        try {
            long startTime = System.currentTimeMillis();

            // 获取实例名
            String catalog = parseDataSourceCatalog(jdbcUrl);
            // 获取对应sql
            String sql = getSql(dbType);
            if (StringUtils.isBlank(catalog) || StringUtils.isBlank(sql)) {
                return null;
            }

            DatabaseMetaInfo metaInfo = new DatabaseMetaInfo();

            Map<String, String> columnTypeMap = new HashMap<>();
            log.info("===============> Begin parsing the {} database {} instance table structure <===============", dbType.getDb(), catalog);
            try (Statement statement = connection.createStatement()) {
                // 解析指定类型字段
                ResultSet resultSet = statement.executeQuery(String.format(sql, String.join(",", TYPE_PATTERN), catalog));
                while (resultSet.next()) {
                    String columnName = resultSet.getString("column_name");
                    String dataType = resultSet.getString("data_type").toUpperCase();
                    columnTypeMap.putIfAbsent(columnName.toLowerCase(), dataType);
                }
            }

            log.info("===============> Parsing {} Instance columnType total time consumed:{}ms <===============", catalog,
                (System.currentTimeMillis() - startTime));

            metaInfo.setDatabaseType(dbType);
            metaInfo.setColumnWithTypeMap(columnTypeMap);

            return metaInfo;
        } catch (Exception e) {
            log.error("Parsing database failed:{}", dbType.getDesc());
        }
        return null;

    }

    /**
     * 获取数据源的实例名
     *
     * @param jdbcUrl
     * @return
     */
    private static String parseDataSourceCatalog(String jdbcUrl) {

        String catalog = null;

        // 针对普通的jdbc url localhost:3306/test?....
        Pattern pattern = Pattern.compile("jdbc:[^:]+://[^/]+/([^?]+)");
        Matcher matcher = pattern.matcher(jdbcUrl);
        if (matcher.find()) {
            catalog = matcher.group(1);
        }

        // 针对dm数据库
        Pattern dmPattern = Pattern.compile("(?<=schema=)[^&]+");
        Matcher dmMatcher = dmPattern.matcher(jdbcUrl);
        if (dmMatcher.find()) {
            catalog = dmMatcher.group(0);
        }

        return catalog;
    }

    /**
     * 根据数据库类型获取系统表查询语句
     *
     * @param dbType
     * @return
     */
    private static String getSql(DbType dbType) {
        switch (dbType) {
            case KINGBASE:
                return KING_BASE_SQL;
            case DM:
                return DM_SQL;
            default:
                return null;
        }
    }
}
